package model;

import java.awt.Dimension;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import evaluator.Evaluator;

import model.entities.LaserBeam;
import model.entities.targets.ITarget;
import model.gameBoard.GameBoard;

/**
 * 
 * Main game model. Holds all world simulation 
 * information.
 * 
 * @author ben
 *
 */
public class GameModel {
	
	private static final Dimension DEFAULT_BOARD_DIMENSION = new Dimension(10,10);
	
	private boolean locked = false;
	private List<IGameModelObserver> observerList = new ArrayList<IGameModelObserver>();
	private GameBoard gameBoard = new GameBoard(DEFAULT_BOARD_DIMENSION);
	private List<LaserBeam> laserBeamList = new ArrayList<LaserBeam>();
	private Evaluator evaluator = new Evaluator(this);
	
	private boolean won = false;
	
	
	public void createNewGameBoard(Dimension dimension) {
		this.gameBoard = new GameBoard(dimension);
	}
	
	public void registerWithModel(IGameModelObserver observer) {
		this.observerList.add(observer);
	}
	
	public void unRegisterWithModel(IGameModelObserver observer) {
		this.observerList.remove(observer);
	}
		
	public synchronized void setDirty() throws ModelLockedException {
		
		if(locked) {
			throw new ModelLockedException();
		}
		
		this.lock();
		
		evaluator.evaluate();
		
		for(IGameModelObserver observer : observerList) {
			observer.onGameModelChange();
		}
		
		this.unLock();
	}
	
	private void lock() {
		this.locked = true;
	}
	
	private void unLock() {
		this.locked = false;
	}

	public GameBoard getGameBoard() {
		return gameBoard;
	}

	public List<LaserBeam> getLaserBeamList() {
		return laserBeamList;
	}

	public void setLaserBeamList(List<LaserBeam> laserBeamList) {
		this.laserBeamList = laserBeamList;
	}
	
	public void clearLaserBeamList() {
		laserBeamList.clear();
	}
	
	public void resetTargets() {
		
		Map<Point, ITarget> targetMap = gameBoard.getTargetMap();
		Set<Point> targetSet = targetMap.keySet();
		
		for (Point point : targetSet) {
			targetMap.get(point).resetTarget();
		}
		
	}

	public synchronized boolean isWon() {
		return won;
	}

	public synchronized void setWon(boolean won) {
		this.won = won;
	}
	
}
